home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / telecomm / terms / term-4.1-source.lha / Extras / Source / term-Source.lha / termLocale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  17.0 KB  |  937 lines

  1. /*
  2. **    termLocale.c
  3. **
  4. **    Localization support routines
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* The catalog data is stored in the following format. */
  13.  
  14. struct CatCompArrayType
  15. {
  16.     LONG    cca_ID;
  17.     STRPTR    cca_Str;
  18. };
  19.  
  20. extern struct CatCompArrayType    *AppStrings;
  21. extern LONG             NumAppStrings;
  22.  
  23.     /* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
  24.      *
  25.      *    Open string translation tables.
  26.      */
  27.  
  28. VOID __regargs
  29. LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
  30. {
  31.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  32.     {
  33.         if(LocaleBase -> lb_SysPatches)
  34.         {
  35.             strcpy(ConvNumber,"%lD");
  36.             strcpy(ConvNumber10,"%10lD");
  37.  
  38.             if(Catalog = OpenCatalog(NULL,CatalogName,
  39.                 OC_BuiltInLanguage,    BuiltIn,
  40.                 OC_BuiltInCodeSet,    0,
  41.             TAG_DONE))
  42.             {
  43.                 BOOL TooOld = FALSE;
  44.  
  45.                     // Don't load an outdated catalog file
  46.  
  47.                 if(Catalog -> cat_Version < Version)
  48.                     TooOld = TRUE;
  49.                 else
  50.                 {
  51.                     if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
  52.                         TooOld = TRUE;
  53.                 }
  54.  
  55.                 if(TooOld)
  56.                 {
  57.                     if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  58.                     {
  59.                         MyEasyRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
  60.  
  61.                         CloseLibrary(IntuitionBase);
  62.  
  63.                         IntuitionBase = NULL;
  64.                     }
  65.  
  66.                     CloseCatalog(Catalog);
  67.  
  68.                     Catalog = NULL;
  69.                 }
  70.             }
  71.  
  72.             Locale = OpenLocale(NULL);
  73.         }
  74.         else
  75.         {
  76.             if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  77.             {
  78.                 MyEasyRequest(NULL,"Your \"locale.library\" is not installed correctly.","Continue");
  79.  
  80.                 CloseLibrary(IntuitionBase);
  81.  
  82.                 IntuitionBase = NULL;
  83.             }
  84.  
  85.             strcpy(ConvNumber,"%ld");
  86.             strcpy(ConvNumber10,"%10ld");
  87.  
  88.             CloseLibrary(LocaleBase);
  89.  
  90.             LocaleBase = NULL;
  91.         }
  92.     }
  93.     else
  94.     {
  95.         strcpy(ConvNumber,"%ld");
  96.         strcpy(ConvNumber10,"%10ld");
  97.     }
  98. }
  99.  
  100.     /* LocaleClose():
  101.      *
  102.      *    Close the translation tables.
  103.      */
  104.  
  105. VOID
  106. LocaleClose()
  107. {
  108.     if(Locale)
  109.     {
  110.         CloseLocale(Locale);
  111.  
  112.         Locale = NULL;
  113.     }
  114.  
  115.     if(Catalog)
  116.     {
  117.         CloseCatalog(Catalog);
  118.  
  119.         Catalog = NULL;
  120.     }
  121.  
  122.     if(LocaleBase)
  123.     {
  124.         CloseLibrary(LocaleBase);
  125.  
  126.         LocaleBase = NULL;
  127.     }
  128. }
  129.  
  130.     /* LanguageCheck():
  131.      *
  132.      *    Checks to see if the currently selected language
  133.      *    is english.
  134.      */
  135.  
  136. VOID
  137. LanguageCheck()
  138. {
  139.     if(Locale && Catalog)
  140.     {
  141.         if(Locale -> loc_LanguageName)
  142.         {
  143.             if(!Stricmp(Locale -> loc_LanguageName,"english.language"))
  144.                 English = TRUE;
  145.             else
  146.                 English = FALSE;
  147.         }
  148.         else
  149.             English = FALSE;
  150.     }
  151.     else
  152.         English = TRUE;
  153. }
  154.  
  155.     /* GadToolsStrlen(STRPTR *String):
  156.      *
  157.      *    Custom version of strlen, useful for gadtools object titles
  158.      *    with embedded underscore characters.
  159.      */
  160.  
  161. WORD __regargs
  162. GadToolsStrlen(STRPTR String)
  163. {
  164.     WORD Len = 0;
  165.  
  166.     while(*String)
  167.     {
  168.         if(*String++ != '_')
  169.             Len++;
  170.     }
  171.  
  172.     return(Len);
  173. }
  174.  
  175.     /* GadToolsLongestString(WORD From,WORD To):
  176.      *
  177.      *    Determines the longest string used by a gadtools
  178.      *    control panel.
  179.      */
  180.  
  181. WORD __regargs
  182. GadToolsLongestString(WORD From,WORD To)
  183. {
  184.     STRPTR    Text;
  185.     WORD    MaxLen = 0,
  186.         Len,i;
  187.  
  188.     for(i = From ; i <= To ; i++)
  189.     {
  190.         if(Text = LocaleString(i))
  191.         {
  192.             if((Len = GadToolsStrlen(Text)) > MaxLen)
  193.                 MaxLen = Len;
  194.         }
  195.     }
  196.  
  197.     return(MaxLen);
  198. }
  199.  
  200.     /* LocaleSeconds(WORD Seconds):
  201.      *
  202.      *    Return seconds in proper format.
  203.      */
  204.  
  205. STRPTR __regargs
  206. LocaleSeconds(WORD Seconds)
  207. {
  208.     STATIC UBYTE Time[10];
  209.  
  210.     if(Locale)
  211.         SPrintf(Time,"%2lD%s%02lD",Seconds / 100,Locale -> loc_DecimalPoint,Seconds % 100);
  212.     else
  213.         SPrintf(Time,"%2ld.%02ld",Seconds / 100,Seconds % 100);
  214.  
  215.     return(Time);
  216. }
  217.  
  218.     /* SmallCurrency():
  219.      *
  220.      *    Support function for the rates control panel, returns a formatted
  221.      *    string to contain a string like "cents/unit".
  222.      */
  223.  
  224. STRPTR
  225. SmallCurrency()
  226. {
  227.     STATIC UBYTE Buffer[30];
  228.  
  229.     if(Locale)
  230.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale -> loc_MonSmallCS);
  231.     else
  232.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
  233.  
  234.     return(Buffer);
  235. }
  236.  
  237.     /* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
  238.      *
  239.      *    Tricky stuff, folks! This beauty will insert grouping characters
  240.      *    into a readily-prepared string buffer filled with numeric
  241.      *    contents. It takes the group separator tokens and group separator
  242.      *    strings into account.
  243.      */
  244.  
  245. VOID __regargs
  246. InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
  247. {
  248.     UBYTE    LocalBuffer[80];    // Sufficient, but too large
  249.     STRPTR    Index;
  250.     LONG    i,j,SeparatorSize;
  251.     WORD    Count;            // How many characters per group
  252.     BOOL    RepeatGroupCount;    // Keep repeating group size until end
  253.  
  254.         // Set up for the first group
  255.  
  256.     switch(*GroupData)
  257.     {
  258.         case 0:            // Repeat current grouping scheme until end
  259.         case 255:        // No further grouping is to be performed
  260.  
  261.             Count = 0;
  262.  
  263.             break;
  264.  
  265.         default:        // Initial group size
  266.  
  267.             RepeatGroupCount = FALSE;
  268.  
  269.             Count = *GroupData++;
  270.  
  271.             break;
  272.     }
  273.  
  274.         // Check the size of the group separator string
  275.  
  276.     if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
  277.         Count = 0;
  278.  
  279.         // That where we'll start
  280.  
  281.     Index = LocalBuffer;
  282.  
  283.         // Build the string back to front, we will reverse it later
  284.  
  285.     for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
  286.     {
  287.             // Pick up the next number character
  288.  
  289.         *Index++ = Buffer[i];
  290.  
  291.             // Are we to insert the grouping characters here?
  292.  
  293.         if(Count && j == Count)
  294.         {
  295.             LONG k;
  296.  
  297.                 // Insert the grouping characters
  298.  
  299.             for(k = SeparatorSize ; k >= 0 ; k--)
  300.                 *Index++ = GroupSeparator[k];
  301.  
  302.                 // Reset the group size counter
  303.  
  304.             j = 0;
  305.  
  306.                 // Pick up the next grouping token?
  307.  
  308.             if(!RepeatGroupCount)
  309.             {
  310.                     // Ok, what kind of token is it?
  311.  
  312.                 switch(*GroupData)
  313.                 {
  314.                     case 0:        // Repeat current grouping scheme
  315.  
  316.                         RepeatGroupCount = TRUE;
  317.                         break;
  318.  
  319.                     case 255:    // Perform no further grouping
  320.  
  321.                         Count = 0;
  322.                         break;
  323.  
  324.                     default:    // New group size
  325.  
  326.                         Count = *GroupData++;
  327.                         break;
  328.                 }
  329.             }
  330.         }
  331.     }
  332.  
  333.         // Look how long the resulting string is
  334.  
  335.     j = (LONG)((ULONG)Index - (ULONG)LocalBuffer) - 1;
  336.  
  337.         // Copy it back
  338.  
  339.     Index = Buffer;
  340.  
  341.         // Reverse the order of characters while copying
  342.  
  343.     for(i = j ; i >= 0 ; i--)
  344.         *Index++ = LocalBuffer[i];
  345.  
  346.         // Provide null-termination
  347.  
  348.     *Index = 0;
  349. }
  350.  
  351. VOID __regargs
  352. ConvertMonetaryQuantity(LONG Units,STRPTR Destination,BOOL UseCurrency)
  353. {
  354.     UBYTE    IntegerBuffer[80];    // Sufficient, but too large
  355.  
  356.     STRPTR    SignText,        // Signed/unsigned quantity text
  357.         SpaceText,        // Currency/number separation
  358.         Currency;        // The name of the currency
  359.     UBYTE    SpaceSep,        // A space separates currency and quantity?
  360.         SignPos,        // Where to place the sign text
  361.         CSPos;            // Where to place the currency text
  362.     BYTE    Sign;            // Negative or positive quantity?
  363.  
  364.         // Negative quantity?
  365.  
  366.     if(Units < 0)
  367.     {
  368.         Sign = -1;
  369.  
  370.         Units = -Units;
  371.     }
  372.     else
  373.         Sign = 1;
  374.  
  375.         // Does this currency sport a fractional smaller currency?
  376.  
  377.     if(Locale -> loc_MonFracDigits)
  378.     {
  379.         UBYTE    NumberBuffer[5],
  380.             FractionBuffer[40];
  381.         LONG    Integer,
  382.             Fraction,
  383.             Scale;
  384.         WORD    i;
  385.  
  386.             // Prepare the formatting string
  387.  
  388.         SPrintf(NumberBuffer,"%%0%ldld",Locale -> loc_MonFracDigits);
  389.  
  390.             // Turn the number of fractional digits into a power of ten
  391.  
  392.         for(i = 0, Scale = 1 ; i < Locale -> loc_MonFracDigits ; i++)
  393.             Scale *= 10;
  394.  
  395.             // Split the quantity in integer and fractional part
  396.  
  397.         Integer        = Units / Scale;
  398.         Fraction    = Units % Scale;
  399.  
  400.             // Build the integer text
  401.  
  402.         SPrintf(IntegerBuffer,"%ld",Integer);
  403.  
  404.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  405.  
  406.             // Build the fractional text
  407.  
  408.         SPrintf(FractionBuffer,NumberBuffer,Fraction);
  409.  
  410.         InsertGrouping(FractionBuffer,Locale -> loc_MonFracGrouping,Locale -> loc_MonFracGroupSeparator);
  411.  
  412.             // Add the monetary decimal point
  413.  
  414.         strcat(IntegerBuffer,Locale -> loc_MonDecimalPoint);
  415.  
  416.             // Add the fractional part
  417.  
  418.         strcat(IntegerBuffer,FractionBuffer);
  419.     }
  420.     else
  421.     {
  422.             // Build the integer text
  423.  
  424.         SPrintf(IntegerBuffer,"%ld",Units);
  425.  
  426.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  427.     }
  428.  
  429.         // Pick up the appropriate formatting parameters
  430.  
  431.     if(Sign < 0)
  432.     {
  433.         SignText    = Locale -> loc_MonNegativeSign;
  434.         SpaceSep    = Locale -> loc_MonNegativeSpaceSep;
  435.         SignPos        = Locale -> loc_MonNegativeSignPos;
  436.         CSPos        = Locale -> loc_MonNegativeCSPos;
  437.     }
  438.     else
  439.     {
  440.         SignText    = Locale -> loc_MonPositiveSign;
  441.         SpaceSep    = Locale -> loc_MonPositiveSpaceSep;
  442.         SignPos        = Locale -> loc_MonPositiveSignPos;
  443.         CSPos        = Locale -> loc_MonPositiveCSPos;
  444.     }
  445.  
  446.         // Are we to use the currency symbol?
  447.  
  448.     if(UseCurrency)
  449.     {
  450.             // Pick up the currency text
  451.  
  452.         Currency = Locale -> loc_MonCS;
  453.  
  454.             // Take care of the separation information
  455.  
  456.         if(SpaceSep == SS_NOSPACE)
  457.             SpaceText = "";
  458.         else
  459.             SpaceText = " ";
  460.     }
  461.     else
  462.         Currency = SpaceText = "";
  463.  
  464.         // Now merge all the information into one single string
  465.  
  466.     if(CSPos == CSP_PRECEDES)
  467.     {
  468.         switch(SignPos)
  469.         {
  470.             case SP_PARENS:
  471.  
  472.                 // Currency (Space) Sign Value
  473.                 SPrintf(Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
  474.                 break;
  475.  
  476.             case SP_PREC_ALL:
  477.  
  478.                 // Sign Currency (Space) Value
  479.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  480.                 break;
  481.  
  482.             case SP_SUCC_ALL:
  483.  
  484.                 // Currency (Space) Value Sign
  485.                 SPrintf(Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
  486.                 break;
  487.  
  488.             case SP_PREC_CURR:
  489.  
  490.                 // Sign Currency (Space) Value
  491.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  492.                 break;
  493.  
  494.             case SP_SUCC_CURR:
  495.  
  496.                 // Currency Sign (Space) Value
  497.                 SPrintf(Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
  498.                 break;
  499.         }
  500.     }
  501.     else
  502.     {
  503.         switch(SignPos)
  504.         {
  505.             case SP_PARENS:
  506.  
  507.                 // Sign Value (Space) Currency
  508.                 SPrintf(Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
  509.                 break;
  510.  
  511.             case SP_PREC_ALL:
  512.  
  513.                 // Sign Value (Space) Currency
  514.                 SPrintf(Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
  515.                 break;
  516.  
  517.             case SP_SUCC_ALL:
  518.  
  519.                 // Value (Space) Currency Sign
  520.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  521.                 break;
  522.  
  523.             case SP_PREC_CURR:
  524.  
  525.                 // Value (Space) Sign Currency
  526.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
  527.                 break;
  528.  
  529.             case SP_SUCC_CURR:
  530.  
  531.                 // Value (Space) Currency Sign
  532.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  533.                 break;
  534.         }
  535.     }
  536. }
  537.  
  538.     /* CreateSum(LONG Quantity):
  539.      *
  540.      *    Create a string containing a monetary quantity formatted
  541.      *    according to the current locale rules.
  542.      */
  543.  
  544. STRPTR __regargs
  545. CreateSum(LONG Quantity,BYTE UseCurrency)
  546. {
  547.     STATIC UBYTE Buffer[100];
  548.  
  549.     if(Locale)
  550.         ConvertMonetaryQuantity(Quantity,Buffer,UseCurrency);
  551.     else
  552.         SPrintf(Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
  553.  
  554.     return(Buffer);
  555. }
  556.  
  557.     /* LocalizeString(STRPTR *Strings,WORD From,WORD To):
  558.      *
  559.      *    Localize an array of strings.
  560.      */
  561.  
  562. VOID __regargs
  563. LocalizeString(STRPTR *Strings,WORD From,WORD To)
  564. {
  565.     WORD i,j;
  566.  
  567.     for(i = From, j = 0 ; i <= To ; i++)
  568.     {
  569.         if(!Strings[j])
  570.             Strings[j++] = LocaleString(i);
  571.     }
  572. }
  573.  
  574.     /* LocalizeStringTable(STRPTR *Strings,LONG *Table)
  575.      *
  576.      *    Localize an array of strings.
  577.      */
  578.  
  579. VOID __regargs
  580. LocalizeStringTable(STRPTR *Strings,LONG *Table)
  581. {
  582.     if(!(*Strings))
  583.     {
  584.         while(*Table != -1)
  585.             *Strings++ = LocaleString(*Table++);
  586.     }
  587. }
  588.  
  589.     /* LocalizeMenu(struct NewMenu *Menu,WORD From):
  590.      *
  591.      *    Localize a NewMenu definition.
  592.      */
  593.  
  594. VOID __regargs
  595. LocalizeMenu(struct NewMenu *Menu,WORD From)
  596. {
  597.     STRPTR Label,Shortcut;
  598.  
  599.         while(Menu -> nm_Type != NM_END)
  600.     {
  601.         Shortcut = LocaleString(From);
  602.  
  603.         if(Shortcut[0] && !Shortcut[1])
  604.             Label = Shortcut + 2;
  605.         else
  606.         {
  607.             Label        = Shortcut;
  608.             Shortcut    = NULL;
  609.         }
  610.  
  611.         switch(Menu -> nm_Type)
  612.         {
  613.             case NM_TITLE:
  614.  
  615.                 Menu -> nm_Label = Label;
  616.  
  617.                 From++;
  618.  
  619.                 break;
  620.  
  621.             case NM_ITEM:
  622.             case NM_SUB:
  623.  
  624.                 if(Menu -> nm_Label != NM_BARLABEL)
  625.                 {
  626.                     Menu -> nm_Label    = Label;
  627.                     Menu -> nm_CommKey    = Shortcut;
  628.  
  629.                     From++;
  630.                 }
  631.  
  632.                 break;
  633.         }
  634.  
  635.         Menu++;
  636.     }
  637. }
  638.  
  639. VOID __regargs
  640. LocalizeMenuTable(struct NewMenu *Menu,LONG *Table)
  641. {
  642.     STRPTR    Label,Shortcut;
  643.     LONG    From = 0;
  644.  
  645.         while(Menu -> nm_Type != NM_END)
  646.     {
  647.         Shortcut = LocaleString(Table[From]);
  648.  
  649.         if(Shortcut[0] && !Shortcut[1])
  650.             Label = Shortcut + 2;
  651.         else
  652.         {
  653.             Label        = Shortcut;
  654.             Shortcut    = NULL;
  655.         }
  656.  
  657.         switch(Menu -> nm_Type)
  658.         {
  659.             case NM_TITLE:
  660.  
  661.                 Menu -> nm_Label = Label;
  662.  
  663.                 From++;
  664.  
  665.                 break;
  666.  
  667.             case NM_ITEM:
  668.             case NM_SUB:
  669.  
  670.                 if(Menu -> nm_Label != NM_BARLABEL)
  671.                 {
  672.                     Menu -> nm_Label    = Label;
  673.                     Menu -> nm_CommKey    = Shortcut;
  674.  
  675.                     From++;
  676.                 }
  677.  
  678.                 break;
  679.         }
  680.  
  681.         Menu++;
  682.     }
  683. }
  684.  
  685.     /* LocaleString(LONG ID):
  686.      *
  687.      *    Obtain a string from the translation pool.
  688.      */
  689.  
  690. STRPTR __regargs
  691. LocaleString(LONG ID)
  692. {
  693.     STRPTR Builtin;
  694.  
  695.     if(ID < NumAppStrings && AppStrings[ID] . cca_ID == ID)
  696.         Builtin = AppStrings[ID] . cca_Str;
  697.     else
  698.     {
  699.         LONG i;
  700.  
  701.         Builtin = "";
  702.  
  703.         for(i = 0 ; i < NumAppStrings ; i++)
  704.         {
  705.             if(AppStrings[i] . cca_ID == ID)
  706.             {
  707.                 Builtin = AppStrings[i] . cca_Str;
  708.  
  709.                 break;
  710.             }
  711.         }
  712.     }
  713.  
  714.     if(Catalog)
  715.     {
  716.         STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
  717.  
  718.         if(String[0])
  719.             return(String);
  720.         else
  721.             return(Builtin);
  722.     }
  723.     else
  724.         return(Builtin);
  725. }
  726.  
  727. STRPTR __saveds __stdargs
  728. LocaleHookFunc(struct Hook *Hook,struct LayoutHandle *Handle,LONG ID)
  729. {
  730.     return(LocaleString(ID));
  731. }
  732.  
  733. STATIC LONG __saveds __asm
  734. FormatDateHookFunc(register __a0 struct Hook *Hook,register __a1 UBYTE Char)
  735. {
  736.     STRPTR String = Hook -> h_Data;
  737.  
  738.     *String++ = Char;
  739.  
  740.     Hook -> h_Data = String;
  741.  
  742.     return(TRUE);
  743. }
  744.  
  745.     /* FormatStamp():
  746.      *
  747.      *    Convert a date stamp into human readable
  748.      *    form by taking the current locale parameters
  749.      *    into account.
  750.      */
  751.  
  752. BOOLEAN __regargs
  753. FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,STRPTR TimeBuffer,STRPTR BothBuffer,BOOLEAN SubstituteDay)
  754. {
  755.     struct DateStamp Now;
  756.  
  757.         // If no time stamp given, do with current time
  758.  
  759.     if(!Stamp)
  760.         DateStamp(Stamp = &Now);
  761.  
  762.         // Is the current locale available?
  763.  
  764.     if(Locale)
  765.     {
  766.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  767.  
  768.             // Combine date and time text?
  769.  
  770.         if(BothBuffer && !SubstituteDay)
  771.         {
  772.             LocalHook . h_Data = BothBuffer;
  773.  
  774.             FormatDate(Locale,Locale -> loc_DateTimeFormat,Stamp,&LocalHook);
  775.  
  776.             StripSpaces(BothBuffer);
  777.         }
  778.         else
  779.         {
  780.             UBYTE    LocalDateBuffer[40],
  781.                 LocalTimeBuffer[40];
  782.  
  783.                 // Provide storage space
  784.  
  785.             if(BothBuffer)
  786.             {
  787.                 DateBuffer = LocalDateBuffer;
  788.                 TimeBuffer = LocalTimeBuffer;
  789.             }
  790.  
  791.                 // Do we have a date buffer to fill?
  792.  
  793.             if(DateBuffer)
  794.             {
  795.                     // Are we to substitute the current day with
  796.                     // text such as today, yesterday, etc.?
  797.  
  798.                 if(SubstituteDay)
  799.                 {
  800.                     struct DateStamp Today;
  801.  
  802.                         // Get the current time
  803.  
  804.                     DateStamp(&Today);
  805.  
  806.                         // Does the date refer to yesterday?
  807.  
  808.                     if(Stamp -> ds_Days == Today . ds_Days - 1)
  809.                         strcpy(DateBuffer,GetLocaleStr(Locale,YESTERDAYSTR));
  810.                     else
  811.                     {
  812.                             // Does the date refer to today?
  813.  
  814.                         if(Stamp -> ds_Days == Today . ds_Days)
  815.                             strcpy(DateBuffer,GetLocaleStr(Locale,TODAYSTR));
  816.                         else
  817.                         {
  818.                                 // Does the date refer to tomorrow?
  819.  
  820.                             if(Stamp -> ds_Days == Today . ds_Days + 1)
  821.                                 strcpy(DateBuffer,GetLocaleStr(Locale,TOMORROWSTR));
  822.                             else
  823.                                 SubstituteDay = NULL;
  824.                         }
  825.                     }
  826.                 }
  827.  
  828.                 if(!SubstituteDay)
  829.                 {
  830.                     LocalHook . h_Data = DateBuffer;
  831.  
  832.                     FormatDate(Locale,Locale -> loc_DateFormat,Stamp,&LocalHook);
  833.                 }
  834.  
  835.                 StripSpaces(DateBuffer);
  836.             }
  837.  
  838.             if(TimeBuffer)
  839.             {
  840.                 LocalHook . h_Data = TimeBuffer;
  841.  
  842.                 FormatDate(Locale,Locale -> loc_TimeFormat,Stamp,&LocalHook);
  843.  
  844.                 StripSpaces(TimeBuffer);
  845.             }
  846.  
  847.                 // Combine date and time
  848.  
  849.             if(BothBuffer)
  850.             {
  851.                 strcpy(BothBuffer,DateBuffer);
  852.                 strcat(BothBuffer," ");
  853.                 strcat(BothBuffer,TimeBuffer);
  854.             }
  855.         }
  856.     }
  857.     else
  858.     {
  859.         struct DateTime    DateTime;
  860.         UBYTE        LocalDateBuffer[40],
  861.                 LocalTimeBuffer[40];
  862.  
  863.             // Provide storage space
  864.  
  865.         if(BothBuffer)
  866.         {
  867.             DateBuffer = LocalDateBuffer;
  868.             TimeBuffer = LocalTimeBuffer;
  869.         }
  870.  
  871.             // No locale, so we will use dos.library instead.
  872.  
  873.         CopyMem(Stamp,&DateTime . dat_Stamp,sizeof(struct DateStamp));
  874.  
  875.         DateTime . dat_Format    = FORMAT_DOS;
  876.         DateTime . dat_Flags    = SubstituteDay ? DTF_SUBST : NULL;
  877.         DateTime . dat_StrDay    = NULL;
  878.         DateTime . dat_StrDate    = DateBuffer;
  879.         DateTime . dat_StrTime    = TimeBuffer;
  880.  
  881.         if(!DateToStr(&DateTime))
  882.             return(FALSE);
  883.  
  884.         if(DateBuffer)
  885.             StripSpaces(DateBuffer);
  886.  
  887.         if(TimeBuffer)
  888.             StripSpaces(TimeBuffer);
  889.  
  890.             // Combine date and time
  891.  
  892.         if(BothBuffer)
  893.         {
  894.             strcpy(BothBuffer,DateBuffer);
  895.             strcat(BothBuffer," ");
  896.             strcat(BothBuffer,TimeBuffer);
  897.         }
  898.     }
  899.  
  900.     return(TRUE);
  901. }
  902.  
  903.     /* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
  904.      *
  905.      *    Given hours, minutes and seconds, format this data into
  906.      *    a human-readable string.
  907.      */
  908.  
  909. VOID __regargs
  910. FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds)
  911. {
  912.     if(Locale)
  913.     {
  914.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  915.  
  916.         struct DateStamp Stamp;
  917.  
  918.         Stamp . ds_Days        = 0;
  919.         Stamp . ds_Minute    = Hours * 60 + Minutes;
  920.         Stamp . ds_Tick        = MAX(0,Seconds) * TICKS_PER_SECOND;
  921.  
  922.         LocalHook . h_Data = Buffer;
  923.  
  924.         if(Seconds < 0)
  925.             FormatDate(Locale,Locale -> loc_ShortTimeFormat,&Stamp,&LocalHook);
  926.         else
  927.             FormatDate(Locale,Locale -> loc_TimeFormat,&Stamp,&LocalHook);
  928.     }
  929.     else
  930.     {
  931.         if(Seconds < 0)
  932.             SPrintf(Buffer,"%02ld:%02ld",Hours,Minutes);
  933.         else
  934.             SPrintf(Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
  935.     }
  936. }
  937.